package com.sc.nft.dao;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sc.nft.entity.SecondOrder;
import com.sc.nft.entity.UserInfo;
import com.sc.nft.entity.dto.*;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.MarketTypeEnum;
import com.sc.nft.enums.OrderStatusEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.mapper.SecondOrderMapper;
import com.sc.nft.pool.UserPool;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 二级订单表(sc_second_order)数据DAO
 *
 * @author kancy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-10-05 12:53:07
 */
@Slf4j
@Repository
@RequiredArgsConstructor
public class SecondOrderDao {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private final SecondOrderEsDao esDao;
    private final SecondOrderDaoAdapter baseDao;
    private final SecondOrderMapper baseMapper;
    private final ApplicationEventPublisher publisher;
    private final UserInfoDao userInfoDao;

    @Repository
    static class SecondOrderDaoAdapter extends ServiceImpl<SecondOrderMapper, SecondOrder> {
        // 为 SecondOrderDao 断舍离~
    }

//    public Page<SecondOrderPageDTO> orderPage(Long userId, int pageNo, int pageSize) {
//        return baseMapper.orderPage(new Page(pageNo, pageSize), userId);
//    }

    public BigDecimal orderNotPayPrice(List<Long> orderIds) {
        List<SecondOrder> orders = baseMapper.selectBatchIds(orderIds);
        if (CollectionUtils.isEmpty(orders)) {
            return BigDecimal.ZERO;
        }
        // 容错逻辑：如果MySQL侧未全部命中，改用ES查询
        if (!Objects.equals(orderIds.size(), orders.size())) {
            log.info("ES批量查询二级订单 ids: {}", orderIds);
            orders = esDao.findByIds(orderIds);
        }
        return orders.stream()
                .filter(entity -> BooleanUtil.isFalse(entity.getIsDelete()))
                .map(SecondOrder::getBuyPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    public List<SecondOrderCollectionListDTO> collectionList(Integer marketType) {
        // 非二级订单查询，不涉及重构 | sc_second_collection_config, sc_digital_collection
        return baseMapper.collectionList(marketType);
    }

    public List<SecondOrderExportListVO> getListByCollectionIdAndTime(List<Long> collectionIdList, Integer marketType, Date startTime, Date endTime) {
        // /admin/second/collectionExport
        return esDao.getListByCollectionIdAndTime(collectionIdList, marketType, startTime, endTime);
    }

    @Deprecated
    List<SecondOrderExportListVO> getListByCollectionIdAndTime0(List<Long> collectionIdList, Integer marketType, Date startTime, Date endTime) {
        return baseMapper.getListByCollectionIdAndTime(collectionIdList, marketType, startTime, endTime);
    }

    public Integer getConsensusCountByCollectionIdAndTime(Long collectionId, Date dealTime) {
        // 查询时间小于30天，走MySQL查询
        return baseDao.lambdaQuery()
                .eq(SecondOrder::getCollectionId, collectionId)
                .ge(SecondOrder::getDealTime, dealTime)
                .eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT)
                .eq(SecondOrder::getIsConsensus, true)
                .count();
    }

    /**
     * 待结算订单列表：分钟级调度来处理，因此查询范围不会超过一天，故完全走MySQL
     *
     * @see com.sc.nft.task.OrderTask#directPushIncome
     */
    public List<SecondOrder> getListByStatusAndIsIncome() {
        LambdaQueryWrapper<SecondOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SecondOrder::getSettleFlag, Boolean.FALSE);
        wrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.orderByAsc(SecondOrder::getId);
        wrapper.last("limit 1500");
        return baseDao.list(wrapper);
    }

    public BigDecimal getMaxPriceByCollectionId(Long collectionId) {
        return esDao.getMaxPriceByCollectionId(collectionId);
    }

    @Deprecated
    BigDecimal getMaxPriceByCollectionId0(Long collectionId) {
        return baseMapper.getMaxPriceByCollectionId(collectionId);
    }

    public BigDecimal getLastPrice(Long collectionId) {
        return esDao.getLastPrice(collectionId);
    }

    @Deprecated
    BigDecimal getLastPrice0(Long collectionId) {
        return baseMapper.getLastPrice(collectionId);
    }

    public SecondOrder selectByRelationIdSubOneDayData(Long collectionId) {
        String key = StrUtil.format("{}:{}", RedisKeyEnum.LEVEL2_ORDERS_GET_THE_LAST_DATA_OF_YESTERDAY, collectionId);
        // 判定对应的KEY是否存在,存在直接反序列化返回.不存在就查询出来写入到缓存在返回.
        Boolean exist = stringRedisTemplate.hasKey(key);
        if (exist) {
            return JSON.parseObject(stringRedisTemplate.opsForValue().get(key), SecondOrder.class);
        }
        // 查询时间小于30天，走MySQL查询
        SecondOrder secondOrder = baseMapper.selectByRelationIdSubOneDayData(collectionId);
        // 把数据序列化以后写入缓存中,保存到第二天凌晨12点过期
        // 计算当前时间,到第二天凌晨的时间差,单位为秒
        stringRedisTemplate.opsForValue().set(key, JSON.toJSONString(secondOrder), secondsToTheNextMorning(), TimeUnit.SECONDS);
        return secondOrder;
    }

    public static long secondsToTheNextMorning() {
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();

        // 获取第二天凌晨的时间（00:00:00）
        LocalDateTime nextDayMidnight = LocalDateTime.of(currentTime.toLocalDate().plusDays(1), LocalTime.MIDNIGHT);

        // 计算时间间隔
        Duration duration = Duration.between(currentTime, nextDayMidnight);

        // 获取间隔的秒数
        return duration.getSeconds();
    }


    public SecondOrder selectBySecondCollectionId(Long secondCollectionId) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.selectBySecondCollectionId(secondCollectionId);
    }

    public List<BrandMarketHistoryDetailsVO> brandMarketHistoryDetails(Long collectionId) {
        // 查询时间（deal_time）小于30天，走MySQL查询 | 理论上 deal_time 与 create_time 相关无几
        return baseMapper.brandMarketHistoryDetails(collectionId);
    }

    /**
     * 新二级商品批量购买的时候的购买列表
     *
     * @param newSecondCollectionGoodsBuyListDTO
     * @return
     */
    public List<NewSecondCollectionGoodsBuyListVO> selectNewSecondCollectionGoodsBuyList(UserInfo userInfo, NewSecondCollectionGoodsBuyListDTO newSecondCollectionGoodsBuyListDTO, Long maxId) {
        // 实际查询 sc_second_collection 表，MySQL包含完整 status=1 数据，故走MySQL查询
        return baseMapper.selectNewSecondCollectionGoodsBuyList(newSecondCollectionGoodsBuyListDTO, userInfo.getId(), maxId);
    }

    public List<NewSecondCollectionGoodsBuyListVO> selectNewSecondCollectionGoodsBuyIds(Long collectionId, List<Long> ids, Long userId, Integer size, Long maxId) {
        // 实际查询 sc_second_collection 表，MySQL包含完整 status=1 数据，故走MySQL查询
        return baseMapper.selectNewSecondCollectionGoodsBuyIds(collectionId, ids, userId, size, maxId);
    }

    public Page<NewSecondCollectionGoodsBuyOrderListVO> selectNewSecondCollectionGoodsSaleOrderList(NewSecondCollectionGoodsBuyOrderListDTO newSecondCollectionGoodsBuyOrderListDTO) {
        return esDao.selectNewSecondCollectionGoodsSaleOrderList(newSecondCollectionGoodsBuyOrderListDTO.toMp(), newSecondCollectionGoodsBuyOrderListDTO, UserPool.getUser().getId());
    }

    @Deprecated
    Page<NewSecondCollectionGoodsBuyOrderListVO> selectNewSecondCollectionGoodsSaleOrderList0(NewSecondCollectionGoodsBuyOrderListDTO newSecondCollectionGoodsBuyOrderListDTO) {
        return baseMapper.selectNewSecondCollectionGoodsSaleOrderList(newSecondCollectionGoodsBuyOrderListDTO.toMp(), newSecondCollectionGoodsBuyOrderListDTO, UserPool.getUser().getId());
    }

    public Page<NewSecondCollectionGoodsBuyOrderListVO> selectNewSecondCollectionGoodsBuyOrderList(NewSecondCollectionGoodsBuyOrderListDTO newSecondCollectionGoodsBuyOrderListDTO) {
        // /newSecondCollection/newSecondCollectionGoodsBuyOrderList
        return esDao.selectNewSecondCollectionGoodsBuyOrderList(newSecondCollectionGoodsBuyOrderListDTO.toMp(), newSecondCollectionGoodsBuyOrderListDTO, UserPool.getUser().getId());
    }

    @Deprecated
    Page<NewSecondCollectionGoodsBuyOrderListVO> selectNewSecondCollectionGoodsBuyOrderList0(NewSecondCollectionGoodsBuyOrderListDTO newSecondCollectionGoodsBuyOrderListDTO) {
        return baseMapper.selectNewSecondCollectionGoodsBuyOrderList(newSecondCollectionGoodsBuyOrderListDTO.toMp(), newSecondCollectionGoodsBuyOrderListDTO, UserPool.getUser().getId());
    }

    public Page<NewSecondCollectionGoodsBuyOrderListVO> overdueOrderList(Page page, Long userId) {
        return esDao.overdueOrderList(page, userId);
    }

    @Deprecated
    Page<NewSecondCollectionGoodsBuyOrderListVO> overdueOrderList0(Page page, Long userId) {
        return baseMapper.overdueOrderList(page, userId);
    }

    public SecondOrder getUserInfoNewOrder() {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getUserInfoNewOrder(UserPool.getUser().getId());
    }

    public List<NewSecondCollectionNotPayOrderVO> getNewSecondCollectionNotPayOrder(Long collectionId) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getNewSecondCollectionNotPayOrder(UserPool.getUser().getId(), collectionId);
    }

    public NewSecondCollectionOrderDetailsVO nweSecondCollectionOrderDetails(Long orderId) {
        return esDao.nweSecondCollectionOrderDetails(orderId, UserPool.getUser().getId());
    }

    @Deprecated
    NewSecondCollectionOrderDetailsVO nweSecondCollectionOrderDetails0(Long orderId) {
        return baseMapper.nweSecondCollectionOrderDetails(orderId, UserPool.getUser().getId());
    }

    public NewSecondCollectionOrderDetailsVO nweSecondCollectionOrderSaleDetails(Long orderId) {
        return esDao.nweSecondCollectionOrderSaleDetails(orderId, UserPool.getUser().getId());
    }

    @Deprecated
    NewSecondCollectionOrderDetailsVO nweSecondCollectionOrderSaleDetails0(Long orderId) {
        return baseMapper.nweSecondCollectionOrderSaleDetails(orderId, UserPool.getUser().getId());
    }

    /**
     * 获取订单前一天最后一条成交数据
     *
     * @param collectionId
     * @return
     */
    public SecondOrder getOrderBeforeDayLastDealData(Long collectionId) {
        // 实际查询的是 T+0 最新一条记录（deal_time），可以认为期查询数据范围不超过30天，故维持MySQL查询
        return baseMapper.getOrderBeforeDayLastDealData(collectionId);
    }

    /**
     * 获取用户待付款订单
     *
     * @return
     */
    public boolean getUserOrderExist(Long userId) {
        // 内置条件 status=1 走MySQL查询
        return baseDao.lambdaQuery().eq(SecondOrder::getBuyUserId, userId).eq(SecondOrder::getStatus, OrderStatusEnum.WAIT_PAY).count() > 0;
    }

    public List<SecondOrder> getPreTimeOutOrderIds(Date time) {
        // 内置条件 status=1 走MySQL查询
        return baseMapper.getPreTimeOutOrderIds(time);
    }

//    public List<Long> userBlackList() {
//        return baseMapper.userBlackList();
//    }

    @Transactional
    public Boolean cancelOrderByOrderId(Long orderId) {
        UpdateWrapper<SecondOrder> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("status", OrderStatusEnum.OVERDUE);
        updateWrapper.set("real_close_time", DateTime.now());
        updateWrapper.eq("id", orderId);
        updateWrapper.eq("status", OrderStatusEnum.WAIT_PAY);
        boolean ret = baseDao.update(new SecondOrder(), updateWrapper);

        // 同步更新ES
        if (ret) {
//            SecondOrder doc = new SecondOrder();
//            doc.setId(orderId);
//            doc.setStatus(OrderStatusEnum.OVERDUE);
//            doc.setRealCloseTime(DateTime.now());
//            esDao.update(doc);
            publisher.publishEvent(new SecondOrderTxEvent(orderId));
        }

        return ret;
    }

    public Boolean isLockOrderBySecondCollectionId(Long secondCollectionId) {
        // 内置条件 status=1 走MySQL查询
        SecondOrder order = baseMapper.isLockOrderBySecondCollectionId(secondCollectionId);
        if (ObjectUtil.isNotNull(order)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    public SecondOrder toDayOrderLimitOneAsc() {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.toDayOrderLimitOneAsc();
    }

    public BigDecimal getSumInCharge() {
        return esDao.getSumInCharge();
    }

    @Deprecated
    BigDecimal getSumInCharge0() {
        return baseMapper.getSumInCharge();
    }

    public BigDecimal getToDaySecondSellAmount() {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDaySecondSellAmount();
    }

//    public BigDecimal getToDaySecondSellAmountByDay(String day) {
//        return baseMapper.getToDaySecondSellAmountByDay(day);
//    }

    public BigDecimal getSecondSellAmount(MarketTypeEnum marketTypeEnum, List<Long> buyUserIds) {
        return esDao.getSecondSellAmount(marketTypeEnum, buyUserIds);
    }

    @Deprecated
    BigDecimal getSecondSellAmount0(MarketTypeEnum marketTypeEnum, List<Long> ids) {
        return baseMapper.getSecondSellAmount(marketTypeEnum.getCode(), ids);
    }

//    public BigDecimal getSecondSellAmountByDay(MarketTypeEnum marketTypeEnum, List<Long> ids, String day) {
//        return baseMapper.getSecondSellAmountByDay(marketTypeEnum.getCode(), ids, day);
//    }

    public BigDecimal getSecondSellAmountByMarketAccount(MarketTypeEnum marketTypeEnum, List<Long> buyUserIds) {
        return esDao.getSecondSellAmountByMarketAccount(marketTypeEnum, buyUserIds);
    }

    @Deprecated
    BigDecimal getSecondSellAmountByMarketAccount0(MarketTypeEnum marketTypeEnum, List<Long> buyUserIds) {
        return baseMapper.getSecondSellAmountByMarketAccount(marketTypeEnum.getCode(), buyUserIds);
    }

//    public BigDecimal getSecondSellAmountByMarketAccountByDay(MarketTypeEnum marketTypeEnum, List<Long> ids, String day) {
//        return baseMapper.getSecondSellAmountByMarketAccountByDay(marketTypeEnum.getCode(), ids, day);
//    }

    public Integer getToDaySellCountByType(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDaySellCountByType(marketType);
    }

//    public Integer getToDaySellCountByTypeByDay(Integer marketType, String day) {
//        return baseMapper.getToDaySellCountByTypeByDay(marketType, day);
//    }

    public BigDecimal getToDaySellAmount(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDaySellAmount(marketType);
    }

//    public BigDecimal getToDaySellAmountByDay(Integer marketType, String day) {
//        return baseMapper.getToDaySellAmountByDay(marketType, day);
//    }

    public Integer getToDaySellBuyUserCount(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDaySellBuyUserCount(marketType);
    }

//    public Integer getToDaySellBuyUserCountByDay(Integer marketType, String day) {
//        return baseMapper.getToDaySellBuyUserCountByDay(marketType, day);
//    }

    public Integer getToDaySellUserCount(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDaySellUserCount(marketType);
    }

//    public Integer getToDaySellUserCountByDay(Integer marketType, String day) {
//        return baseMapper.getToDaySellUserCountByDay(marketType, day);
//    }

    public List<SecondOrder> getOrderListByMarketType(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getOrderListByMarketType(marketType);
    }

//    public List<SecondOrder> getOrderListByMarketTypeByDay(Integer marketType, String day) {
//        return baseMapper.getOrderListByMarketTypeByDay(marketType, day);
//    }

    /**
     * 获取用户当天被锁数据
     *
     * @param userId
     * @return
     */
    public AdminSecondOrderNowDataLockVO nowDataLockOrderSize(Long userId) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.nowDataLockOrderSize(userId);
    }

    public BigDecimal getToDayBuyPayBalancePriceByType(Integer marketType) {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.getToDayBuyPayBalancePriceByType(marketType);
    }

//    public BigDecimal getToDayBuyPayBalancePriceByTypeByDay(Integer marketType, String day) {
//        return baseMapper.getToDayBuyPayBalancePriceByTypeByDay(marketType, day);
//    }

    public TodaySHighAndLowPricesVO todaySHighAndLowPrices(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.todaySHighAndLowPrices(id);
    }

    public TodaySHighAndLowPricesVO todaySHighAndLowPricesForConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.todaySHighAndLowPricesForConsensus(id);
    }

    public TodaySHighAndLowPricesVO todaySHighAndLowPricesNotInConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.todaySHighAndLowPricesNotInConsensus(id);
    }

    public BigDecimal latestTransactionPrice(Long collectionId) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.latestTransactionPrice(collectionId);
    }

    public BigDecimal latestTransactionPriceForConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.latestTransactionPriceForConsensus(id);
    }

    public BigDecimal latestTransactionPriceNotInConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.latestTransactionPriceNotInConsensus(id);
    }

    public int dailyTurnover(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.dailyTurnover(id);
    }

    public int dailyTurnoverForConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.dailyTurnoverForConsensus(id);
    }

    public int dailyTurnoverNotInConsensus(Long id) {
        // 查询时间范围小于30天（deal_time）
        return baseMapper.dailyTurnoverNotInConsensus(id);
    }

    public Page<FlowRecordVO> flowRecord(FlowRecordDTO flowRecordDTO) {
        return esDao.flowRecord(flowRecordDTO.toMp(), flowRecordDTO);
    }

    @Deprecated
    Page<FlowRecordVO> flowRecord0(FlowRecordDTO flowRecordDTO) {
        return baseMapper.flowRecord(flowRecordDTO.toMp(), flowRecordDTO);
    }

    public Page<FlowRecordVO> flowRecordForConsensus(FlowRecordDTO flowRecordDTO) {
        return esDao.flowRecordWithConsensus(flowRecordDTO.toMp(), flowRecordDTO, true);
    }

    @Deprecated
    Page<FlowRecordVO> flowRecordForConsensus0(FlowRecordDTO flowRecordDTO) {
        return baseMapper.flowRecordForConsensus(flowRecordDTO.toMp(), flowRecordDTO);
    }

    public Page<FlowRecordVO> flowRecordNotInConsensus(FlowRecordDTO flowRecordDTO) {
        return esDao.flowRecordWithConsensus(flowRecordDTO.toMp(), flowRecordDTO, false);
    }

    @Deprecated
    Page<FlowRecordVO> flowRecordNotInConsensus0(FlowRecordDTO flowRecordDTO) {
        return baseMapper.flowRecordNotInConsensus(flowRecordDTO.toMp(), flowRecordDTO);
    }

    /**
     * 查询待结算业绩订单
     */
    public List<SecondOrder> getWithSettlePerformance() {
        return esDao.getWithSettlePerformance();
    }

    @Deprecated
    List<SecondOrder> getWithSettlePerformance0() {
        LambdaQueryWrapper<SecondOrder> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(SecondOrder::getId, SecondOrder::getBuyUserId, SecondOrder::getCharge,
                SecondOrder::getDealTime, SecondOrder::getBuyPrice, SecondOrder::getShareProfitPanelId);
        wrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.eq(SecondOrder::getPerformanceSettleFlag, false);
        wrapper.orderByAsc(SecondOrder::getId);
        wrapper.last("limit 20000");
        return baseDao.list(wrapper);
    }

    public List<DingLianDealPracticalVO> dealPracticalInConsensus() {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.dealPracticalInConsensus();
    }

    public List<DingLianDealPracticalVO> dealPracticalNotInConsensus() {
        // 查询时间小于30天，走MySQL查询
        return baseMapper.dealPracticalNotInConsensus();
    }

    public List<DingLianTransactionRecordVO> transactionRecord(DingLianTransactionRecordDTO dto) {
        // 与伟成确认参数时间范围小于30天，走MySQL查询
        return baseMapper.transactionRecord(dto);
    }

    public Page<CollectionSimpleVO> getPageSecondaryMarketCollection(Integer pageNo, Integer pageSize) {
        // 非二级订单查询，不涉及重构
        return baseMapper.getPageSecondaryMarketCollection(new Page(pageNo, pageSize));
    }

    public List<ConsignmentRecordVO> consignmentRecord(Long id, Integer limit) {
        // 实际查询 sc_second_collection 表，MySQL包含完整 status=1 数据，故走MySQL查询
        return baseMapper.consignmentRecord(id, limit);
    }

    public List<ConsignmentRecordVO> consignmentRecordForConsensus(Long id, Integer limit) {
        // 实际查询 sc_second_collection 表，MySQL包含完整 status=1 数据，故走MySQL查询
        return baseMapper.consignmentRecordForConsensus(id, limit);
    }

    public Page<Long> idPage(Long buyUserId, Long saleUserId, Long collectionId, Date startTime, Date endTime, Integer marketType, int pageNo, int pageSize) {
        return esDao.idPage(new Page<>(pageNo, pageSize), buyUserId, saleUserId, collectionId, startTime, endTime, marketType);
    }

    @Deprecated
    Page<Long> idPage0(Long buyUserId, Long saleUserId, Long collectionId, Date startTime, Date endTime, Integer marketType, int pageNo, int pageSize) {
        Page<Object> objectPage = new Page<>(pageNo, pageSize);
        objectPage.setSearchCount(false);
        objectPage.setTotal(baseMapper.idCountPage(buyUserId, saleUserId, collectionId, startTime, endTime, marketType));
        return baseMapper.idPage(new Page<>(pageNo, pageSize), buyUserId, saleUserId, collectionId, startTime, endTime, marketType);
    }

    public List<SecondOrderDTO> adminPageByIdList(List<Long> ids) {
        return esDao.adminPageByIdList(ids);
    }

    @Deprecated
    List<SecondOrderDTO> adminPageByIdList0(List<Long> ids) {
        return baseMapper.adminPageByIdList(ids);
    }

    /**
     * 与WWC确认三方拉取数据之用，拉取数据为最近数据，30天内数据可走MySQL查询
     *
     * @see ExplorationOfWisdomController#tradeList | /api/ztan/trade-list
     */
    public List<ZhiTanTradeVO> tradeList(List<Long> idList) {
        return baseMapper.tradeList(idList);
    }

    /**
     * 查询数据范围为30天内数，走MySQL查询
     *
     * @see #tradeList(List)
     */
    public List<Long> tradeIdList(DateTime date, Integer limit) {
        return baseMapper.tradeIdList(date, limit);
    }

    @Transactional
    public void allReadySettleFlag(Long id) {
        Assert.isTrue(baseDao.lambdaUpdate()
                        .eq(SecondOrder::getId, id)
                        .eq(SecondOrder::getSettleFlag, false)
                        .set(SecondOrder::getSettleFlag, true)
                        .update(),
                () -> new GlobalRunTimeException("订单结算状态更新失败"));

        // 同步更新ES
//        SecondOrder doc = new SecondOrder();
//        doc.setId(id);
//        doc.setSettleFlag(true);
//        esDao.update(doc);
        publisher.publishEvent(new SecondOrderTxEvent(id));
    }

    @Transactional
    public void allReadyPerformanceSettleFlag(Long id) {
        boolean ret = baseDao.lambdaUpdate()
                .eq(SecondOrder::getId, id)
                .eq(SecondOrder::getPerformanceSettleFlag, false)
                .set(SecondOrder::getPerformanceSettleFlag, true)
                .update();

        if (!ret) {
            log.warn("订单业绩结算状态更新失败 id: {}", id);
        }

        // 同步更新ES
//        SecondOrder doc = new SecondOrder();
//        doc.setId(id);
//        doc.setPerformanceSettleFlag(true);
//        esDao.update(doc);
        publisher.publishEvent(new SecondOrderTxEvent(id));
    }

    public IPage<SecondaryMarketSearchVO> marketSearch(SecondaryMarketSearchDTO request) {
        // 非二级订单查询，不涉及重构
        return baseMapper.marketSearch(request, request.toMp());
    }

    public SecondOverdueOrderDetailsVO overdueOrderDetails(Long orderId, Long userId) {
        return esDao.overdueOrderDetails(orderId, userId);
    }

    @Deprecated
    SecondOverdueOrderDetailsVO overdueOrderDetails0(Long orderId, Long userId) {
        return baseMapper.overdueOrderDetails(orderId, userId);
    }

    public IPage<RefundOrderPageVO> refundOrderPage(RefundOrderPageDTO request, Long userId) {
        return esDao.refundOrderPage(request, userId);
    }

    @Deprecated
    IPage<RefundOrderPageVO> refundOrderPage0(RefundOrderPageDTO request, Long userId) {
        LambdaQueryWrapper<SecondOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.select(SecondOrder::getOrderNo, SecondOrder::getFirstTitle, SecondOrder::getBuyPrice,
                SecondOrder::getStatus, SecondOrder::getCreateTime, SecondOrder::getPayTime);
        wrapper.eq(SecondOrder::getBuyUserId, userId);
        wrapper.eq(request.getStatus() != null, SecondOrder::getStatus, request.getStatus());
        wrapper.eq(StrUtil.isNotEmpty(request.getOrderNo()), SecondOrder::getOrderNo, request.getOrderNo());
        wrapper.orderByDesc(SecondOrder::getId);
        Page page = baseDao.page(request.toMp(), wrapper);
        List<SecondOrder> records = page.getRecords();
        List<RefundOrderPageVO> refundOrderPageVOS = BeanUtil.copyToList(records, RefundOrderPageVO.class);
        page.setRecords(refundOrderPageVOS);
        return page;
    }

    public SecondOrder getById(Long id) {
        // 容错逻辑：MySQL未命中时查询ES
        return Optional.ofNullable(baseDao.getById(id)).orElse(esDao.findById(id));
    }

    @Transactional
    public boolean updateById(SecondOrder entity) {
        boolean ret = baseDao.updateById(entity);
//        esDao.update(entity);
        publisher.publishEvent(new SecondOrderTxEvent(entity.getId()));
        return ret;
    }

    @Transactional
    public boolean save(SecondOrder entity) {
        boolean ret = baseDao.save(entity);
        // esDao.save(entity); // 改用Event监控机制实现，解决事务回滚造成的数据不同步问题
        publisher.publishEvent(new SecondOrderTxEvent(entity.getId()));
        return ret;
    }

    /**
     * 同步ES事件
     */
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT, classes = SecondOrderTxEvent.class)
    void onTxEvent(SecondOrderTxEvent event) {
        Long id = event.getPk();
        SecondOrder entity = getById(id);
        if (entity != null) {
            esDao.save(entity);
        }
    }

    /**
     * SecondOrder 事务事件
     */
    @Getter
    public static class SecondOrderTxEvent extends ApplicationEvent {

        private static final long serialVersionUID = 7608695579660865889L;
        private final Long pk;

        public SecondOrderTxEvent(long pk) {
            super(pk);
            this.pk = pk;
        }
    }

//    public List<SecondOrder> list(Wrapper<SecondOrder> wrapper) {
//        return baseDao.list(wrapper);
//    }

    public Integer countOrder(Long userId) {
        return esDao.countOrder(userId);
    }

    @Deprecated
    Integer countOrder0(Long userId) {
        LambdaQueryWrapper<SecondOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SecondOrder::getBuyUserId, userId);
        queryWrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
//        queryWrapper.last(" limit 5");
//        return baseDao.list(queryWrapper).size();

        // 虽然不知道为啥，但原实现就是这个！！
        return Math.min(baseDao.count(queryWrapper), 5);
    }

    public List<SecondOrder> listByIds(List<Long> orderIds) {
        if (CollectionUtils.isEmpty(orderIds)) {
            return new ArrayList<>();
        }

        List<SecondOrder> list = baseDao.listByIds(orderIds);

        // 优先查询MySQL数据，若未完全命中则走ES查询
        if (CollectionUtils.isEmpty(list) || list.size() < orderIds.size()) {
            list = esDao.findByIds(orderIds);
        }

        return list;
    }

    public BigDecimal getToDaySumCharge(Integer type, Integer marketType, Date startTime, Date endTime) {
        // 实际查询的是昨天数据，查询范围在30天内，走MySQL查询
        // com.sc.nft.admin.task.SandQywxNoticTask#sendMsg5
        return baseMapper.getToDaySumCharge(type, marketType, startTime, endTime);
    }

    public Integer getMarketUserCount(Integer marketType, Date startTime, Date endTime) {
        // 实际查询的是昨天数据，查询范围在30天内，走MySQL查询
        // com.sc.nft.admin.task.SandQywxNoticTask#sendMsg5
        return baseMapper.getMarketUserCount(marketType, startTime, endTime);
    }

    public BigDecimal getMonthlyStatistics(Integer type, Integer marketType, Date startTime, Date endTime) {
        // 实际查询的是上个月的数据，查询范围在60天内，走MySQL查询
        // com.sc.nft.admin.task.SandQywxNoticTask#sendMsg3
        return baseMapper.getMonthlyStatistics(type, marketType, startTime, endTime);
    }

    /**
     * 滚动同步MySQL数据到ES
     */
    public void syncToEs(Long collectionId, String userTel) {

        final String key = String.format("data:sync:sc_second_collection:%d:user:%s", collectionId, userTel);

        if (!stringRedisTemplate.opsForValue().setIfAbsent(key, "1", Duration.ofMinutes(5))) {
            log.info("表 sc_second_collection 数据同步中 collectionId: {}, userTel: {}", collectionId, userTel);
            return;
        }

        Long userId = null;
        if (StrUtil.isNotBlank(userTel)) {
            UserInfo user = userInfoDao.getByUserTel(userTel);
            if (user != null) {
                userId = user.getId();
            }
        }

        if (collectionId == null && userId == null) {
            log.warn("请求参数错误（藏品或手机号不能同时为空）");
            stringRedisTemplate.delete(key);
            return;
        }

        log.info("表 sc_second_collection 数据开始同步 collectionId: {}, userTel: {}", collectionId, userTel);

        // 遍历 sc_second_collection 数据
        LambdaQueryWrapper<SecondOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(collectionId != null, SecondOrder::getCollectionId, collectionId);
        wrapper.eq(userId != null, SecondOrder::getBuyUserId, userId);

        int pageNo = 1;
        int limit = 1000;
        for (; ; pageNo++) {
            // 分页查询
            Page<SecondOrder> page = baseDao.page(new Page<>(pageNo, limit, false), wrapper);
            if (CollectionUtils.isEmpty(page.getRecords())) {
                break;
            }

            // 执行同步
            try {
                esDao.bulkIndex(page.getRecords());
            } catch (IOException e) {
                log.error("同步ES数据出错", e);
            }

            if (page.getRecords().size() < limit) {
                break;
            }
        }

        stringRedisTemplate.delete(key);
    }

    public IPage<SecondOrder> wantBuyOrderPage(Page page, Long wantBuyOrderId) {
        LambdaQueryWrapper<SecondOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SecondOrder::getIsSecondWantBuyOrder, Boolean.TRUE);
        wrapper.eq(SecondOrder::getSecondWantBuyOrderId, wantBuyOrderId);
        wrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.orderByDesc(SecondOrder::getCreateTime);
        return baseMapper.selectPage(page, wrapper);
    }

    public IPage<SecondOrder> wantBuyOrderPage(Page page, Long wantBuyOrderId, Long salesUserId, Date startCreateTime, Date endCreateTime, Date startPayTime, Date endPayTime) {
        LambdaQueryWrapper<SecondOrder> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SecondOrder::getIsSecondWantBuyOrder, Boolean.TRUE);
        wrapper.eq(SecondOrder::getSecondWantBuyOrderId, wantBuyOrderId);
        wrapper.eq(Objects.nonNull(salesUserId), SecondOrder::getSalesUserId, salesUserId);
        wrapper.ge(Objects.nonNull(startCreateTime), SecondOrder::getCreateTime, startCreateTime);
        wrapper.le(Objects.nonNull(endCreateTime), SecondOrder::getCreateTime, endCreateTime);
        wrapper.ge(Objects.nonNull(startPayTime), SecondOrder::getPayTime, startPayTime);
        wrapper.le(Objects.nonNull(endPayTime), SecondOrder::getPayTime, endPayTime);
        wrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
        wrapper.orderByDesc(SecondOrder::getCreateTime);
        return baseMapper.selectPage(page, wrapper);
    }


}